const fs = require('fs')
const os = require('os')
const path = require('path')
const sharp = require('sharp')
const XLSX = require('xlsx')
// 配置
const config = {
	filePath: './images/', // 处理的图片文件夹
	dist: './images-cut/', // 处理完成的图片文件夹
	index: 0, // 序号
	logPath: './images-cut/log.txt', // 操作日志
	surplusImage: './images-cut/错误文件列表.txt', // 统计其他非图片文件
	noFilePath: './images-cut/异常的图片.txt', // 异常的不合法的图片文件
	// 匹配规则 通过keys 来匹配生成相对于的新文件名
	rules: [
		{ newName: '1总', keys: ['总'] },
		{ newName: '2峰', keys: ['峰'] },
		{ newName: '3谷', keys: ['谷'] },
		{ newName: '4金额', keys: ['剩余金额', '金额'] },
		{ newName: '5换前', keys: ['剩余金额', '时间'] },
		{ newName: '6换中', keys: ['换前', '前'] },
		{ newName: '7换后', keys: ['换后', '前'] },
		{ newName: '8模块', keys: ['新电表采集模块', '8新电表采集模块'] },
	],
	// 需要忽略的图片名
	ignorekeys: ['其他文件', '前 - 副本', '电价'],
}
let arrList = []
let num = 0
let num2 = 0
// 转XLSX
const toXLSX = (_data, name) => {
	try {
		console.log('------->日志输出正在生成excle:', _data.length)
		const _headers = [
			{ key: 'district', title: '片区' },
			{ key: 'area', title: '台区' },
			{ key: 'user', title: '用户' },
			{ key: 'num', title: '原图片数量' },
			{ key: 'num2', title: '现图片数量' },
		]
		const headers = _headers.map(({ title }) => title)

			.map((v, i) => Object.assign({}, { v: v, position: String.fromCharCode(65 + i) + 1 }))

			.reduce((prev, next) => Object.assign({}, prev, {
				[next.position]: { v: next.v }
			}), {})

		const data = _data
			// 匹配 headers 的位置，生成对应的单元格数据
			.map((v, i) => _headers.map(({ key }, j) => Object.assign({}, { v: v[key], position: String.fromCharCode(65 + j) + (i + 2) })))
			// 对刚才的结果进行降维处理（二维数组变成一维数组）
			.reduce((prev, next) => prev.concat(next))
			.reduce((prev, next) => Object.assign({}, prev, {
				[next.position]: { v: next.v }
			}), {})

		// 合并 headers 和 data
		const output = Object.assign({}, headers, data)

		// 获取所有单元格的位置
		const outputPos = Object.keys(output)

		// 计算出范围
		const ref = outputPos[0] + ':' + outputPos[outputPos.length - 1]

		// 构建 workbook 对象
		const wb = {
			SheetNames: ['sheet1'],
			Sheets: {
				'sheet1': Object.assign({}, output, { '!ref': ref })
			}
		}
		// 导出 Excel
		XLSX.writeFile(wb, `${ name }.xlsx`)
		// return result.data
	} catch (e) {
		console.log('--------->xlsx处理错误', e)
	}
}
// 生成新图片
const newImage = async ({ image, width, height, filePath }) => {
	try {
		config.index = config.index + 1
		let newPath = filePath.replace(config.filePath, config.dist) // 源地址=>新地址
		console.log(`--------->生成新图片${ config.index }`, width, height, newPath)
		await image.extract({ left: 0, top: 0, width, height }).toFile(newPath) // 生成新图片
	} catch (e) {
		//TODO handle the exception
		console.log('------->生成新图片错误e', e)
	}

}
// 保存图片的方法
const savePngFile = async (file, filePath) => {
	// console.log('------->日志输出filePath:', filePath)
	let extname = path.extname(filePath)
	isImage = ['.jpg', '.png', '.JPG', '.PNG'].includes(extname)
	// console.log('--------->isImage', isImage)
	fs.appendFileSync(config.logPath, filePath + os.EOL, { encoding: 'utf-8' }) // 更新
	// 如果不是标准的图片 保存并记录
	if (!isImage) {
		console.log('--------->不是标准的图片', extname)
		let file = fs.readFileSync(filePath)
		let newPath = filePath.replace(config.filePath, config.dist) // 源地址=>新地址
		fs.writeFileSync(newPath, file)
		return fs.appendFileSync(config.surplusImage, filePath + os.EOL, { encoding: 'utf-8' }) // 更新
	}
	// console.log('------->处理图片filePath:', filePath)
	// 剩下的都是标准的图片了 
	try {
		let arr = filePath.split('/') // 拆分文件路径得到台区名称 用户名称
		let district = arr[2] // 片区名称
		let area = arr[3] // 台区名称
		let user = arr[4] // 用户
		// 如果是第一行 或者是第一个用户
		if (arrList.length === 0 || user !== arrList[arrList.length - 1].user) {
			arrList.push({ district: '', area: '', user: '', num: '', num2: '' }) // 用于后面替换计算
			num = 0
			num2 = 0
		}
		num += 1 // 原图片数量默认+1
		// console.log('------->解析图片', )
		const image = sharp(filePath) // 解析图片
		// console.log('------->获取图片信息', )
		let { width, height } = await image.metadata() // 获取图片信息
		// console.log('------->日志输出width, height:', width, height)
		let isNoFilePath = true // 默认属于未处理图片
		let fileName = file.replace(/(.*\/)*([^.]+).*/ig, '$2') // 文件名
		// console.log('------->日志输出fileName:', fileName)
		// 根据匹配规则来处理图片
		// console.log('------->日志输出file:', file)
		for (let rule of config.rules) {
			// 匹配当前图片是否属于修改后的命名，如果存在直接复制
			if (rule.newName === fileName) {
				newImage({ image, width, height, filePath })
				isNoFilePath = false
				num2 += 1 // 新图片数量+1
			}
			// 匹配成功 修改
			if (rule.keys.includes(fileName)) {
				// console.log('------->日志输出rule.keys:', rule.newName, fileName, rule.keys, )
				let _file = file.replace(fileName, rule.newName) //  把abc.png 改成1.abc.png
				let _filePath = filePath.replace(file, _file) // 把a/b/c/abc.png 改成a/b/c/1.abc.png
				newImage({ image, width, height, filePath: _filePath })
				isNoFilePath = false
				num2 += 1 // 新图片数量+1
			}
		}
		// console.log('------->日志输出isNoFilePath:', isNoFilePath)
		// 没有匹配规则
		if (isNoFilePath && !config.ignorekeys.includes(fileName)) {
			fs.appendFileSync(config.noFilePath, filePath + os.EOL, { encoding: 'utf-8' }) // 记录没有任何处理规则的图片
			newImage({ image, width, height, filePath }) // 其他图片照常复制
			num2 += 1 // 新图片数量+1
		}
		arrList.splice(arrList.length - 1, 1, { district, area, user, num, num2 }) // 更正图片数量
		// console.log('------->日志输出arrList:', arrList)
	} catch (e) {
		console.log('------->处理图片出错:', e)
		fs.appendFileSync(config.surplusImage, filePath + os.EOL, { encoding: 'utf-8' }) // 更新
	}
}

// 清空文件夹
const delDir = async (path) => {
	let files = []
	if (fs.existsSync(path)) {
		files = fs.readdirSync(path)
		for (let file of files) {
			let curPath = path + '/' + file
			// console.log('--------->curPath', curPath)
			if (fs.statSync(curPath).isDirectory()) {
				await delDir(curPath) //递归删除文件夹
			} else {
				fs.unlinkSync(curPath) //删除文件
			}
		}
		fs.rmdirSync(path) // 删除当前文件夹
	}
}

// 解析目录
const analysisDirectory = async (path, isfirst = false) => {
	path = path ? path : config.filePath // 当前的目录路径
	// 首次执行需要清楚上一次所记录的surplusImage
	if (isfirst) {
		await delDir(config.dist) // 清空dist
		fs.mkdirSync(config.dist, '0755') //创建当前文件夹
		fs.appendFileSync(config.surplusImage, '') // 错误格式
		// fs.writeFileSync(config.surplusImage, '')
		fs.appendFileSync(config.noFilePath, '') // 记录没有任何处理规则的图片
		// return
	}
	const fileList = fs.readdirSync(path) // 读取目录所有文件
	// 空文件的时候也需要统添加为0的统计数据
	if (fileList.length === 0) {
		let arr = path.split('/')
		if (arr.length > 5) {
			let area = arr[3]
			let user = arr[4]
			arrList.push({ area, user, num: 0, num2: 0 })
		}
	}
	// 从根目录开始遍历
	for (let file of fileList) {
		let _path = `${ path }${ file }`
		let isDirectory = fs.statSync(_path).isDirectory() // 判断当前file是否为文件夹
		if (isDirectory) {
			let newDirectory = _path.replace(config.filePath, config.dist)
			fs.mkdirSync(newDirectory) // 还需要创建一个对应的cut文件夹
			_path = `${ _path }/`
			// console.log('--------->是文件', index, _path)
			await analysisDirectory(_path)
			continue
		}
		// console.log('--------->index', _path)
		await savePngFile(file, _path) // 处理文件
	}
}
// 多加个fun 来计算一下时间 默认使用同步操作以降低性能开销和保证稳定性，如果你电脑性能强大，那么也可以在上面savePngFile() 中去掉开头的await,此时下面的时间计算无效
const init = async () => {
	let start = new Date().getTime() // 开始时间
	await analysisDirectory(null, true) // 执行解析
	await toXLSX(arrList, './images-cut/查错统计') //使用业务逻辑层的方法返回值
	let end = new Date().getTime() // 结束时间
	console.log(`--------->处理完成,消耗${ ((end - start) / 1000).toFixed(2) }s`, )
}
init()
/**
 * 			佛曰:
 * 				写字楼里写字间，写字间里程序员；
 * 				程序人员写程序，又拿程序换酒钱。
 * 				酒醒只在网上坐，酒醉还来网下眠；
 * 				酒醉酒醒日复日，网上网下年复年。
 * 				但愿老死电脑间，不愿鞠躬老板前；
 * 				奔驰宝马贵者趣，公交自行程序员。
 * 				别人笑我忒疯癫，我笑自己命太贱；
 * 				不见满街漂亮妹，哪个归得程序员？
 *
 * @description 批量修改指定的图片名称，错误的文件和未匹配上的图片都会生成记录，并且统计每个台区文件夹下的图片数量，
 * @tutorial 暂无参考文档
 * @param {String} paramsName = 未知的参数
 * @event 暂无事件
 * @example 暂无示例
 * @return {String} {暂无返回值}
 * @author Breathe
 */
